<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=2">
<meta name="theme-color" content="#222">
<meta name="generator" content="Hexo 5.4.2">
  <link rel="apple-touch-icon" sizes="180x180" href="/blog/images/icon.png">
  <link rel="icon" type="image/png" sizes="32x32" href="/blog/images/icon.png">
  <link rel="icon" type="image/png" sizes="16x16" href="/blog/images/icon.png">
  <link rel="mask-icon" href="/blog/images/icon.svg" color="#222">

<link rel="stylesheet" href="/blog/css/main.css">


<link rel="stylesheet" href="/blog/lib/font-awesome/css/all.min.css">

<script id="hexo-configurations">
    var NexT = window.NexT || {};
    var CONFIG = {"hostname":"bgape002.gitee.io","root":"/blog/","scheme":"Gemini","version":"7.8.0","exturl":false,"sidebar":{"position":"left","display":"post","padding":18,"offset":12,"onmobile":false},"copycode":{"enable":true,"show_result":true,"style":"mac"},"back2top":{"enable":true,"sidebar":false,"scrollpercent":true},"bookmark":{"enable":false,"color":"#222","save":"auto"},"fancybox":false,"mediumzoom":false,"lazyload":false,"pangu":false,"comments":{"style":"tabs","active":null,"storage":true,"lazyload":false,"nav":null},"algolia":{"hits":{"per_page":10},"labels":{"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}},"localsearch":{"enable":true,"trigger":"auto","top_n_per_article":1,"unescape":false,"preload":false},"motion":{"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"slideDownIn","post_body":"slideDownIn","coll_header":"slideLeftIn","sidebar":"slideUpIn"}},"path":"search.xml"};
  </script>

  <meta name="description" content="什么是socket socket起源于Unix，而Unix&#x2F;Linux基本哲学之一就是“一切皆文件”，对于文件用【打开】【读写】【关闭】模式来操作。socket就是该模式的一个实现，socket即是一种特殊的文件，一些socket函数就是对其进行的操作（读&#x2F;写IO、打开、关闭） 基本上，Socket 是任何一种计算机网络通讯中最基础的内容。例如当你在浏览器地址栏中输入 http:&#x2F;&#x2F;www.cnb">
<meta property="og:type" content="article">
<meta property="og:title" content="socket编程">
<meta property="og:url" content="https://bgape002.gitee.io/2022/08/05/socket%E7%BC%96%E7%A8%8B/index.html">
<meta property="og:site_name" content="bgape002">
<meta property="og:description" content="什么是socket socket起源于Unix，而Unix&#x2F;Linux基本哲学之一就是“一切皆文件”，对于文件用【打开】【读写】【关闭】模式来操作。socket就是该模式的一个实现，socket即是一种特殊的文件，一些socket函数就是对其进行的操作（读&#x2F;写IO、打开、关闭） 基本上，Socket 是任何一种计算机网络通讯中最基础的内容。例如当你在浏览器地址栏中输入 http:&#x2F;&#x2F;www.cnb">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://bgape002.gitee.io/blog/images/tcp_socket.png">
<meta property="article:published_time" content="2022-08-05T07:27:03.000Z">
<meta property="article:modified_time" content="2022-08-24T07:44:59.073Z">
<meta property="article:author" content="bgape002">
<meta property="article:tag" content="computer records">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://bgape002.gitee.io/blog/images/tcp_socket.png">

<link rel="canonical" href="https://bgape002.gitee.io/2022/08/05/socket%E7%BC%96%E7%A8%8B/">


<script id="page-configurations">
  // https://hexo.io/docs/variables.html
  CONFIG.page = {
    sidebar: "",
    isHome : false,
    isPost : true,
    lang   : 'zh-CN'
  };
</script>

  <title>socket编程 | bgape002</title>
  






  <noscript>
  <style>
  .use-motion .brand,
  .use-motion .menu-item,
  .sidebar-inner,
  .use-motion .post-block,
  .use-motion .pagination,
  .use-motion .comments,
  .use-motion .post-header,
  .use-motion .post-body,
  .use-motion .collection-header { opacity: initial; }

  .use-motion .site-title,
  .use-motion .site-subtitle {
    opacity: initial;
    top: initial;
  }

  .use-motion .logo-line-before i { left: initial; }
  .use-motion .logo-line-after i { right: initial; }
  </style>
</noscript>

</head>

<body itemscope itemtype="http://schema.org/WebPage">
  <div class="container use-motion">
    <div class="headband"></div>

    <header class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-brand-container">
  <div class="site-nav-toggle">
    <div class="toggle" aria-label="切换导航栏">
      <span class="toggle-line toggle-line-first"></span>
      <span class="toggle-line toggle-line-middle"></span>
      <span class="toggle-line toggle-line-last"></span>
    </div>
  </div>

  <div class="site-meta">

    <a href="/blog/" class="brand" rel="start">
      <span class="logo-line-before"><i></i></span>
      <h1 class="site-title">bgape002</h1>
      <span class="logo-line-after"><i></i></span>
    </a>
      <p class="site-subtitle" itemprop="description">淡泊明志，宁静致远</p>
  </div>

  <div class="site-nav-right">
    <div class="toggle popup-trigger">
        <i class="fa fa-search fa-fw fa-lg"></i>
    </div>
  </div>
</div>




<nav class="site-nav">
  <ul id="menu" class="main-menu menu">
        <li class="menu-item menu-item-home">

    <a href="/blog/" rel="section"><i class="fa fa-home fa-fw"></i>首页</a>

  </li>
        <li class="menu-item menu-item-tags">

    <a href="/blog/tags/" rel="section"><i class="fa fa-tags fa-fw"></i>标签<span class="badge">66</span></a>

  </li>
        <li class="menu-item menu-item-categories">

    <a href="/blog/categories/" rel="section"><i class="fa fa-th fa-fw"></i>分类<span class="badge">27</span></a>

  </li>
        <li class="menu-item menu-item-archives">

    <a href="/blog/archives/" rel="section"><i class="fa fa-archive fa-fw"></i>归档<span class="badge">61</span></a>

  </li>
      <li class="menu-item menu-item-search">
        <a role="button" class="popup-trigger"><i class="fa fa-search fa-fw"></i>搜索
        </a>
      </li>
  </ul>
</nav>



  <div class="search-pop-overlay">
    <div class="popup search-popup">
        <div class="search-header">
  <span class="search-icon">
    <i class="fa fa-search"></i>
  </span>
  <div class="search-input-container">
    <input autocomplete="off" autocapitalize="off"
           placeholder="搜索..." spellcheck="false"
           type="search" class="search-input">
  </div>
  <span class="popup-btn-close">
    <i class="fa fa-times-circle"></i>
  </span>
</div>
<div id="search-result">
  <div id="no-result">
    <i class="fa fa-spinner fa-pulse fa-5x fa-fw"></i>
  </div>
</div>

    </div>
  </div>

</div>
    </header>

    
  <div class="back-to-top">
    <i class="fa fa-arrow-up"></i>
    <span>0%</span>
  </div>


    <main class="main">
      <div class="main-inner">
        <div class="content-wrap">
          

          <div class="content post posts-expand">
            

    
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="https://bgape002.gitee.io/2022/08/05/socket%E7%BC%96%E7%A8%8B/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/blog/images/head.png">
      <meta itemprop="name" content="bgape002">
      <meta itemprop="description" content="mail: bgape002@163.com">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="bgape002">
    </span>
      <header class="post-header">
        <h1 class="post-title" itemprop="name headline">
          socket编程
        </h1>

        <div class="post-meta">
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-calendar"></i>
              </span>
              <span class="post-meta-item-text">发表于</span>

              <time title="创建时间：2022-08-05 15:27:03" itemprop="dateCreated datePublished" datetime="2022-08-05T15:27:03+08:00">2022-08-05</time>
            </span>
              <span class="post-meta-item">
                <span class="post-meta-item-icon">
                  <i class="far fa-calendar-check"></i>
                </span>
                <span class="post-meta-item-text">更新于</span>
                <time title="修改时间：2022-08-24 15:44:59" itemprop="dateModified" datetime="2022-08-24T15:44:59+08:00">2022-08-24</time>
              </span>

          
            <span class="post-meta-item" title="阅读次数" id="busuanzi_container_page_pv" style="display: none;">
              <span class="post-meta-item-icon">
                <i class="fa fa-eye"></i>
              </span>
              <span class="post-meta-item-text">阅读次数：</span>
              <span id="busuanzi_value_page_pv"></span>
            </span>
  
  <span class="post-meta-item">
    
      <span class="post-meta-item-icon">
        <i class="far fa-comment"></i>
      </span>
      <span class="post-meta-item-text">Valine：</span>
    
    <a title="valine" href="/blog/2022/08/05/socket%E7%BC%96%E7%A8%8B/#valine-comments" itemprop="discussionUrl">
      <span class="post-comments-count valine-comment-count" data-xid="/blog/2022/08/05/socket%E7%BC%96%E7%A8%8B/" itemprop="commentCount"></span>
    </a>
  </span>
  
  

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
        <h3 id="什么是socket"><a href="#什么是socket" class="headerlink" title="什么是socket"></a>什么是socket</h3><ul>
<li>socket起源于Unix，而Unix/Linux基本哲学之一就是“一切皆文件”，对于文件用【打开】【读写】【关闭】模式来操作。<strong>socket就是该模式的一个实现，socket即是一种特殊的文件，一些socket函数就是对其进行的操作（读/写IO、打开、关闭）</strong></li>
<li>基本上，<strong>Socket 是任何一种计算机网络通讯中最基础的内容。</strong>例如当你在浏览器地址栏中输入 <a target="_blank" rel="noopener" href="http://www.cnblogs.com/">http://www.cnblogs.com/</a> 时，你会打开一个套接字，然后连接到 <a target="_blank" rel="noopener" href="http://www.cnblogs.com/">http://www.cnblogs.com/</a> 并读取响应的页面然后然后显示出来。而其他一些聊天客户端如 gtalk 和 skype 也是类似。任何网络通讯都是通过 Socket 来完成的。</li>
<li><strong>socket和file的区别</strong><ol>
<li>file 模块是针对某个指定文件进行【打开】【读写】【关闭】</li>
<li>socket 模块是针对 服务器端 和 客户端Socket 进行【打开】【读写】【关闭</li>
</ol>
</li>
</ul>
<h3 id="socket编程流程"><a href="#socket编程流程" class="headerlink" title="socket编程流程"></a>socket编程流程</h3><p><img src="/blog/images/tcp_socket.png" alt="."></p>
<span id="more"></span>

<h3 id="socket参数"><a href="#socket参数" class="headerlink" title="socket参数"></a>socket参数</h3><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* -- socket类型 -- */</span></span><br><span class="line"></span><br><span class="line">socket<span class="selector-class">.AF_UNIX</span>				<span class="comment">/* 只能够用于单一的Unix系统进程间通信 */</span></span><br><span class="line">socket<span class="selector-class">.AF_INET</span>    			<span class="comment">/* 服务器之间网络通信 */</span></span><br><span class="line">socket<span class="selector-class">.AF_INET6</span>				<span class="comment">/* IPv6 */</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">socket<span class="selector-class">.SOCK_STREAM</span>			<span class="comment">/* 流式socket , for TCP */</span></span><br><span class="line">socket<span class="selector-class">.SOCK_DGRAM</span>			<span class="comment">/* 数据报式socket , for UDP */</span></span><br><span class="line">socket<span class="selector-class">.SOCK_RAW</span>				<span class="comment">/* 原始套接字，普通的套接字无法处理ICMP、IGMP等网络报文，而SOCK_RAW可以；其次，SOCK_RAW也可以处理特殊的IPv4报文；此外，利用原始套接字，可以通过IP_HDRINCL套接字选项由用户构造IP头。 */</span></span><br><span class="line">socket<span class="selector-class">.SOCK_SEQPACKET</span>		<span class="comment">/* 可靠的连续数据包服务 */</span></span><br></pre></td></tr></table></figure>

<ul>
<li><strong>socket函数</strong><ol>
<li>TCP 发送数据时，已建立好TCP连接，所以不需要指定地址</li>
<li>UDP 是面向无连接的，每次发送要指定是发给谁</li>
<li>服务端与客户端不能直接发送列表，元组，字典，需要字符串化</li>
</ol>
</li>
</ul>
<figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* ------------------------- 服务端socket函数 -------------------------- */</span></span><br><span class="line">s<span class="selector-class">.bind</span>(<span class="selector-tag">address</span>)</span><br><span class="line"><span class="comment">/* 将套接字绑定到地址, 在AF_INET下,以元组（host,port）的形式表示地址 */</span></span><br><span class="line"></span><br><span class="line">s<span class="selector-class">.listen</span>(backlog)</span><br><span class="line"><span class="comment">/* 开始监听TCP传入连接。backlog指定在拒绝连接之前，操作系统可以挂起的最大连接数量。该值至少为1， backlog等于5，表示内核已经接到了连接请求，但服务器还没有调用accept进行处理的连接个数最大为5，这个值不能无限大，因为要在内核中维护连接队列 */</span></span><br><span class="line"></span><br><span class="line">s<span class="selector-class">.accept</span>()</span><br><span class="line"><span class="comment">/* 接受TCP连接并返回（conn,address）,其中conn是新的套接字对象，可以用来接收和发送数据。address是连接客户端的地址 */</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* ------------------------- 客户端socket函数 ------------------------- */</span></span><br><span class="line">s<span class="selector-class">.connect</span>(<span class="selector-tag">address</span>)</span><br><span class="line"><span class="comment">/* 连接到address处的套接字。一般address的格式为元组（hostname,port），如果连接出错，返回socket.error错误 */</span></span><br><span class="line"></span><br><span class="line">s<span class="selector-class">.connect_ex</span>(adddress)</span><br><span class="line"><span class="comment">/* 功能与connect(address)相同，但是成功返回0，失败返回errno的值 */</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* --------------------------- 共有socket函数 -------------------------- */</span></span><br><span class="line">s<span class="selector-class">.recv</span>(bufsize<span class="selector-attr">[,flag]</span>)</span><br><span class="line"><span class="comment">/* 接受TCP套接字的数据。数据以字符串形式返回，bufsize指定要接收的最大数据量。flag提供有关消息的其他信息，通常可以忽略 */</span></span><br><span class="line"></span><br><span class="line">s<span class="selector-class">.send</span>(string<span class="selector-attr">[,flag]</span>)</span><br><span class="line"><span class="comment">/* 发送TCP数据。将string中的数据发送到连接的套接字。返回值是要发送的字节数量，该数量可能小于string的字节大小 */</span></span><br><span class="line"></span><br><span class="line">s<span class="selector-class">.sendall</span>(string<span class="selector-attr">[,flag]</span>)</span><br><span class="line"><span class="comment">/* 完整发送TCP数据。将string中的数据发送到连接的套接字，但在返回之前会尝试发送所有数据。成功返回None，失败则抛出异常 */</span></span><br><span class="line"></span><br><span class="line">s<span class="selector-class">.recvfrom</span>(bufsize<span class="selector-attr">[.flag]</span>)</span><br><span class="line"><span class="comment">/* 接受UDP套接字的数据。与recv()类似，但返回值是（data,address）。其中data是包含接收数据的字符串，address是发送数据的套接字地址 */</span></span><br><span class="line"></span><br><span class="line">s<span class="selector-class">.sendto</span>(string<span class="selector-attr">[,flag]</span>,<span class="selector-tag">address</span>)</span><br><span class="line"><span class="comment">/* 发送UDP数据。将数据发送到套接字，address是形式为（ipaddr，port）的元组，指定远程地址。返回值是发送的字节数 */</span></span><br><span class="line"></span><br><span class="line">s<span class="selector-class">.close</span>()</span><br><span class="line"><span class="comment">/* 关闭套接字 */</span></span><br><span class="line"></span><br><span class="line">s<span class="selector-class">.getpeername</span>()</span><br><span class="line"><span class="comment">/* 返回连接套接字的远程地址。返回值通常是元组（ipaddr,port） */</span></span><br><span class="line"></span><br><span class="line">s<span class="selector-class">.getsockname</span>()</span><br><span class="line"><span class="comment">/* 返回套接字自己的地址。通常是一个元组(ipaddr,port) */</span></span><br><span class="line"></span><br><span class="line">s<span class="selector-class">.setsockopt</span>(level,optname,value)</span><br><span class="line"><span class="comment">/* 设置给定套接字选项的值 */</span></span><br><span class="line"></span><br><span class="line">s<span class="selector-class">.getsockopt</span>(level,optname<span class="selector-attr">[.buflen]</span>)</span><br><span class="line"><span class="comment">/* 返回套接字选项的值  */</span></span><br><span class="line"></span><br><span class="line">s<span class="selector-class">.settimeout</span>(timeout)</span><br><span class="line"><span class="comment">/* 设置套接字操作的超时期，timeout是一个浮点数，单位是秒。值为None表示没有超时期。一般，超时期应该在刚创建套接字时设置，因为它们可能用于连接的操作（如connect()） */</span></span><br><span class="line"></span><br><span class="line">s<span class="selector-class">.gettimeout</span>()</span><br><span class="line"><span class="comment">/* 返回当前超时期的值，单位是秒，如果没有设置超时期，则返回None */</span></span><br><span class="line"></span><br><span class="line">s<span class="selector-class">.fileno</span>()</span><br><span class="line"><span class="comment">/* 返回套接字的文件描述符  */</span></span><br><span class="line"></span><br><span class="line">s<span class="selector-class">.setblocking</span>(flag)</span><br><span class="line"><span class="comment">/* 如果flag为0，则将套接字设为非阻塞模式，否则将套接字设为阻塞模式（默认值）。非阻塞模式下，如果调用recv()没有发现任何数据，或send()调用无法立即发送数据，那么将引起socket.error异常 */</span></span><br><span class="line"></span><br><span class="line">s<span class="selector-class">.makefile</span>()</span><br><span class="line"><span class="comment">/* 创建一个与该套接字相关连的文件 */</span></span><br></pre></td></tr></table></figure>



<h3 id="简单的服务器和客户端通信"><a href="#简单的服务器和客户端通信" class="headerlink" title="简单的服务器和客户端通信"></a>简单的服务器和客户端通信</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">&quot;&quot;&quot;服务端</span></span><br><span class="line"><span class="string">file: service.py</span></span><br><span class="line"><span class="string">socket service</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">&quot;&quot;&quot;</span></span><br><span class="line"> </span><br><span class="line">    </span><br><span class="line"><span class="keyword">import</span> socket</span><br><span class="line"><span class="keyword">import</span> threading</span><br><span class="line"><span class="keyword">import</span> time</span><br><span class="line"><span class="keyword">import</span> sys</span><br><span class="line"> </span><br><span class="line"> </span><br><span class="line"><span class="keyword">def</span> <span class="title function_">socket_service</span>():</span><br><span class="line">    <span class="keyword">try</span>:</span><br><span class="line">        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)</span><br><span class="line">        <span class="comment"># 防止socket server重启后端口被占用（socket.error: [Errno 98] Address already in use）</span></span><br><span class="line">        s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, <span class="number">1</span>)</span><br><span class="line">        s.bind((<span class="string">&#x27;127.0.0.1&#x27;</span>, <span class="number">6666</span>))</span><br><span class="line">        <span class="comment"># s.bind((&#x27;127.0.0.1&#x27;,0))     # 0 指定端口号为0，则表示随机给一个为占用的端口号</span></span><br><span class="line">        s.listen(<span class="number">10</span>)</span><br><span class="line">    <span class="keyword">except</span> socket.error <span class="keyword">as</span> msg:</span><br><span class="line">        <span class="built_in">print</span>(msg)</span><br><span class="line">        sys.exit(<span class="number">1</span>)</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">&#x27;Waiting connection...&#x27;</span>)</span><br><span class="line"> </span><br><span class="line">    <span class="keyword">while</span> <span class="number">1</span>:</span><br><span class="line">        conn, addr = s.accept()</span><br><span class="line">        t = threading.Thread(target=deal_data, args=(conn, addr))</span><br><span class="line">        t.start()</span><br><span class="line"> </span><br><span class="line"><span class="keyword">def</span> <span class="title function_">deal_data</span>(<span class="params">conn, addr</span>):</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">&#x27;Accept new connection from &#123;0&#125;&#x27;</span>.<span class="built_in">format</span>(addr))</span><br><span class="line">    conn.send((<span class="string">&#x27;Hi, Welcome to the server!&#x27;</span>).encode())</span><br><span class="line">    <span class="keyword">while</span> <span class="number">1</span>:</span><br><span class="line">        data = conn.recv(<span class="number">1024</span>)</span><br><span class="line">        <span class="built_in">print</span>(<span class="string">&#x27;&#123;0&#125; client send data is &#123;1&#125;&#x27;</span>.<span class="built_in">format</span>(addr, data.decode()))<span class="comment">#b&#x27;\xe8\xbf\x99\xe6\xac\xa1\xe5\x8f\xaf\xe4\xbb\xa5\xe4\xba\x86&#x27;</span></span><br><span class="line">        time.sleep(<span class="number">1</span>)</span><br><span class="line">        <span class="keyword">if</span> data == <span class="string">&#x27;exit&#x27;</span> <span class="keyword">or</span> <span class="keyword">not</span> data:</span><br><span class="line">            <span class="built_in">print</span>(<span class="string">&#x27;&#123;0&#125; connection close&#x27;</span>.<span class="built_in">format</span>(addr))</span><br><span class="line">            conn.send(<span class="built_in">bytes</span>(<span class="string">&#x27;Connection closed!&#x27;</span>),<span class="string">&#x27;UTF-8&#x27;</span>)</span><br><span class="line">            <span class="keyword">break</span></span><br><span class="line">        conn.send(<span class="built_in">bytes</span>(<span class="string">&#x27;Hello, &#123;0&#125;&#x27;</span>.<span class="built_in">format</span>(data),<span class="string">&quot;UTF-8&quot;</span>))<span class="comment">#TypeError: a bytes-like object is required, not &#x27;str&#x27;</span></span><br><span class="line">    conn.close()</span><br><span class="line"> </span><br><span class="line"> </span><br><span class="line"><span class="keyword">if</span> __name__ == <span class="string">&#x27;__main__&#x27;</span>:</span><br><span class="line">    socket_service()</span><br></pre></td></tr></table></figure>



<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">&quot;&quot;&quot;客户端</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">&quot;&quot;&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> socket</span><br><span class="line"><span class="keyword">import</span> sys</span><br><span class="line"> </span><br><span class="line"> </span><br><span class="line"><span class="keyword">def</span> <span class="title function_">socket_client</span>():</span><br><span class="line">    <span class="keyword">try</span>:</span><br><span class="line">        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)</span><br><span class="line">        s.connect((<span class="string">&#x27;127.0.0.1&#x27;</span>, <span class="number">6666</span>))</span><br><span class="line">    <span class="keyword">except</span> socket.error <span class="keyword">as</span> msg:</span><br><span class="line">        <span class="built_in">print</span>(msg)</span><br><span class="line">        sys.exit(<span class="number">1</span>)</span><br><span class="line">    <span class="built_in">print</span>(s.recv(<span class="number">1024</span>))<span class="comment">#目的在于接受：Accept new connection from (...</span></span><br><span class="line">    <span class="keyword">while</span> <span class="number">1</span>:</span><br><span class="line">        data = <span class="built_in">input</span>(<span class="string">&#x27;please input work: &#x27;</span>).encode()</span><br><span class="line">        s.send(data)</span><br><span class="line">        <span class="built_in">print</span>(<span class="string">&#x27;aa&#x27;</span>,s.recv(<span class="number">1024</span>))</span><br><span class="line">        <span class="keyword">if</span> data.decode() == <span class="string">&#x27;exit&#x27;</span>:</span><br><span class="line">            <span class="keyword">break</span></span><br><span class="line">    s.close()</span><br><span class="line"> </span><br><span class="line"> </span><br><span class="line"><span class="keyword">if</span> __name__ == <span class="string">&#x27;__main__&#x27;</span>:</span><br><span class="line">    socket_client()</span><br></pre></td></tr></table></figure>



<h3 id="socket文件传输"><a href="#socket文件传输" class="headerlink" title="socket文件传输"></a>socket文件传输</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">&quot;&quot;</span>服务器端server.py</span><br><span class="line"></span><br><span class="line"><span class="string">&quot;&quot;</span></span><br><span class="line"><span class="keyword">import</span> socket</span><br><span class="line"><span class="keyword">import</span> os</span><br><span class="line"><span class="keyword">import</span> sys</span><br><span class="line"><span class="keyword">import</span> struct</span><br><span class="line"> </span><br><span class="line"> </span><br><span class="line"><span class="keyword">def</span> <span class="title function_">socket_service_image</span>():</span><br><span class="line">    <span class="keyword">try</span>:</span><br><span class="line">        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)</span><br><span class="line">        s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, <span class="number">1</span>)</span><br><span class="line">        <span class="comment"># s.bind((&#x27;127.0.0.1&#x27;, 6666))</span></span><br><span class="line">        s.bind((<span class="string">&#x27;127.0.0.1&#x27;</span>, <span class="number">6666</span>))</span><br><span class="line">        s.listen(<span class="number">10</span>)</span><br><span class="line">    <span class="keyword">except</span> socket.error <span class="keyword">as</span> msg:</span><br><span class="line">        <span class="built_in">print</span>(msg)</span><br><span class="line">        sys.exit(<span class="number">1</span>)</span><br><span class="line"> </span><br><span class="line">    <span class="built_in">print</span>(<span class="string">&quot;Wait for Connection.....................&quot;</span>)</span><br><span class="line"> </span><br><span class="line">    <span class="keyword">while</span> <span class="literal">True</span>:</span><br><span class="line">        sock, addr = s.accept()  <span class="comment"># addr是一个元组(ip,port)</span></span><br><span class="line">        deal_image(sock, addr)</span><br><span class="line"> </span><br><span class="line"> </span><br><span class="line"><span class="keyword">def</span> <span class="title function_">deal_image</span>(<span class="params">sock, addr</span>):</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">&quot;Accept connection from &#123;0&#125;&quot;</span>.<span class="built_in">format</span>(addr))  <span class="comment"># 查看发送端的ip和端口</span></span><br><span class="line"> </span><br><span class="line">    <span class="keyword">while</span> <span class="literal">True</span>:</span><br><span class="line">        fileinfo_size = struct.calcsize(<span class="string">&#x27;128sq&#x27;</span>)</span><br><span class="line">        <span class="built_in">print</span>(<span class="string">&#x27;fileinfo_size is&#x27;</span>,fileinfo_size)</span><br><span class="line">        buf = sock.recv(fileinfo_size)  <span class="comment"># 接收图片名</span></span><br><span class="line">        <span class="built_in">print</span>(<span class="string">&#x27;buf is &#x27;</span>,buf)</span><br><span class="line">        <span class="keyword">if</span> buf:</span><br><span class="line">            filename, filesize = struct.unpack(<span class="string">&#x27;128sq&#x27;</span>, buf)</span><br><span class="line">            <span class="built_in">print</span>(<span class="string">&#x27;filename ,filesize is&#x27;</span>,filename.decode(),filesize )</span><br><span class="line">            fn = filename.decode().strip(<span class="string">&#x27;\x00&#x27;</span>)</span><br><span class="line">            <span class="built_in">print</span>(<span class="string">&#x27;fn is &#x27;</span>,fn)</span><br><span class="line">            new_filename = os.path.join(<span class="string">&#x27;./&#x27;</span>, <span class="string">&#x27;new_&#x27;</span> + fn)  </span><br><span class="line">            <span class="comment"># 在服务器端新建图片名（可以不用新建的，直接用原来的也行，只要客户端和服务器不是同一个系统或接收到的图片和原图片不在一个文件夹下）</span></span><br><span class="line"> </span><br><span class="line">            recvd_size = <span class="number">0</span></span><br><span class="line">            fp = <span class="built_in">open</span>(new_filename, <span class="string">&#x27;wb&#x27;</span>)</span><br><span class="line"> </span><br><span class="line">            <span class="keyword">while</span> <span class="keyword">not</span> recvd_size == filesize:</span><br><span class="line">                <span class="keyword">if</span> filesize - recvd_size &gt; <span class="number">1024</span>:</span><br><span class="line">                    data = sock.recv(<span class="number">1024</span>)</span><br><span class="line">                    recvd_size += <span class="built_in">len</span>(data)</span><br><span class="line">                <span class="keyword">else</span>:</span><br><span class="line">                    data = sock.recv(<span class="number">1024</span>)</span><br><span class="line">                    recvd_size = filesize</span><br><span class="line">                <span class="built_in">print</span>(<span class="string">&#x27;data is&#x27;</span>,data)</span><br><span class="line">                fp.write(data)  <span class="comment"># 写入图片数据</span></span><br><span class="line">            fp.close()</span><br><span class="line">        sock.close()</span><br><span class="line">        <span class="keyword">break</span></span><br><span class="line"> </span><br><span class="line"> </span><br><span class="line"><span class="keyword">if</span> __name__ == <span class="string">&#x27;__main__&#x27;</span>:</span><br><span class="line">    socket_service_image()</span><br></pre></td></tr></table></figure>



<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">&#x27;&#x27;&#x27;客户端client.py</span></span><br><span class="line"><span class="string">Fuction：客户端发送图片和数据</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">&#x27;&#x27;&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> socket</span><br><span class="line"><span class="keyword">import</span> os</span><br><span class="line"><span class="keyword">import</span> sys</span><br><span class="line"><span class="keyword">import</span> struct</span><br><span class="line"> </span><br><span class="line"> </span><br><span class="line"><span class="keyword">def</span> <span class="title function_">sock_client_image</span>():</span><br><span class="line">    <span class="keyword">while</span> <span class="literal">True</span>:</span><br><span class="line">        <span class="keyword">try</span>:</span><br><span class="line">            s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)</span><br><span class="line">            s.connect((<span class="string">&#x27;127.0.0.1&#x27;</span>, <span class="number">6666</span>))  </span><br><span class="line">            <span class="comment"># 服务器和客户端在不同的系统或不同的主机下时使用的ip和端口，首先要查看服务器所在的系统网卡的ip</span></span><br><span class="line">            <span class="comment"># s.connect((&#x27;127.0.0.1&#x27;, 6666))  #服务器和客户端都在一个系统下时使用的ip和端口</span></span><br><span class="line">        <span class="keyword">except</span> socket.error <span class="keyword">as</span> msg:</span><br><span class="line">            <span class="built_in">print</span>(msg)</span><br><span class="line">            <span class="built_in">print</span>(sys.exit(<span class="number">1</span>))</span><br><span class="line">        filepath = <span class="built_in">input</span>(<span class="string">&#x27;input the file: &#x27;</span>)  <span class="comment"># 输入当前目录下的图片名 xxx.jpg</span></span><br><span class="line">        fhead = struct.pack(<span class="string">b&#x27;128sq&#x27;</span>, <span class="built_in">bytes</span>(os.path.basename(filepath), encoding=<span class="string">&#x27;utf-8&#x27;</span>),</span><br><span class="line">                            os.stat(filepath).st_size)  <span class="comment"># 将xxx.jpg以128sq的格式打包</span></span><br><span class="line">        s.send(fhead)</span><br><span class="line"> </span><br><span class="line">        fp = <span class="built_in">open</span>(filepath, <span class="string">&#x27;rb&#x27;</span>)  <span class="comment"># 打开要传输的图片</span></span><br><span class="line">        <span class="keyword">while</span> <span class="literal">True</span>:</span><br><span class="line">            data = fp.read(<span class="number">1024</span>)  <span class="comment"># 读入图片数据</span></span><br><span class="line">            <span class="keyword">if</span> <span class="keyword">not</span> data:</span><br><span class="line">                <span class="built_in">print</span>(<span class="string">&#x27;&#123;0&#125; send over...&#x27;</span>.<span class="built_in">format</span>(filepath))</span><br><span class="line">                <span class="keyword">break</span></span><br><span class="line">            s.send(data)  <span class="comment"># 以二进制格式发送图片数据</span></span><br><span class="line">        s.close()</span><br><span class="line">        <span class="comment"># break    #循环发送</span></span><br><span class="line"> </span><br><span class="line"> </span><br><span class="line"><span class="keyword">if</span> __name__ == <span class="string">&#x27;__main__&#x27;</span>:</span><br><span class="line">    sock_client_image()</span><br></pre></td></tr></table></figure>



<h3 id="socketserver"><a href="#socketserver" class="headerlink" title="socketserver"></a>socketserver</h3><p>socket 编程过于底层，编程虽然有套路，但是想要写出健壮的代码还是比较困难的</p>
<p><strong>socketserver</strong> 模块对socket底层 API进行了封装，它是网络服务编程框架，便于企业级快速开发</p>
<h4 id="类的继承关系"><a href="#类的继承关系" class="headerlink" title="类的继承关系"></a>类的继承关系</h4><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">+------------+</span><br><span class="line">| BaseServer |</span><br><span class="line">+------------+</span><br><span class="line">    |</span><br><span class="line">    v</span><br><span class="line">+-----------+        +------------------+</span><br><span class="line">| TCPServer |-------&gt;| UnixStreamServer |</span><br><span class="line">+-----------+        +------------------+</span><br><span class="line">    |</span><br><span class="line">    v</span><br><span class="line">+-----------+        +--------------------+</span><br><span class="line">| UDPServer |-------&gt;| UnixDatagramServer |</span><br><span class="line">+-----------+        +--------------------+</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<ul>
<li><strong>有4个同步类</strong><ol>
<li>TCPServer</li>
<li>UDPServer</li>
<li>UnixStreamServer</li>
<li>UnixDatagramServer</li>
</ol>
</li>
<li><strong>两个Mixin类，用来支持异步</strong><ol>
<li>ForkingMixIn</li>
<li>ThreadingMixIn</li>
</ol>
</li>
<li><strong>组合得到</strong><ol>
<li>class ForkingUDPServer(ForkingMixIn,UDPServer):pass</li>
<li>class ForkingTCPServer(ForkingMixIn,TCPServer):pass</li>
<li>class ThreadingUDPServer(ThreadingMixIn,UDPServer):pass</li>
<li>class ThreadingTCPServer(ThreadingMixIn,TCPServer):pass</li>
</ol>
</li>
<li>fork是创建多进程，thread是创建多线程</li>
<li>fork需要操作系统支持，Windows不支持</li>
<li><strong>ThreadingUDPServer与ThreadingTCPServer类中的特有属性</strong>：<ol>
<li>daemon_threads=False # 默认值是False表示创建的线程都不是daemon线程，改为True表示创建的所有线程都是daemon线程</li>
<li>block_on_close=False # 默认值为Fasle，如果为True，可以设置为守护线程3.7版本可以用</li>
</ol>
</li>
</ul>
<h4 id="编程接口"><a href="#编程接口" class="headerlink" title="编程接口"></a>编程接口</h4><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self, server_address, RequestHandlerClass</span>):</span><br><span class="line">    <span class="string">&quot;&quot;&quot;Constructor.  May be extended, do not override.</span></span><br><span class="line"><span class="string">    	1. server_address 			#服务器绑定的地址信息，是一个元组(ip,prost)</span></span><br><span class="line"><span class="string">		2. RequestHandlerClass 		#必须是BaseRequestHandler的一个子类</span></span><br><span class="line"><span class="string">    &quot;&quot;&quot;</span></span><br><span class="line">    self.server_address = server_address</span><br><span class="line">    self.RequestHandlerClass = RequestHandlerClass</span><br><span class="line">    self.__is_shut_down = threading.Event()</span><br><span class="line">    self.__shutdown_request = <span class="literal">False</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 处理请求的方法，会实例化一个RequestHandlerClass对象</span></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">finish_request</span>(<span class="params">self, request, client_address</span>):</span><br><span class="line">    <span class="string">&quot;&quot;&quot;Finish one request by instantiating RequestHandlerClass.&quot;&quot;&quot;</span></span><br><span class="line">    self.RequestHandlerClass(request, client_address, self)</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* BaseServer中定义的接口常用属性和方法 */</span></span><br><span class="line"></span><br><span class="line">server_address	</span><br><span class="line"><span class="comment">/* 服务器正在监听的地址和端口，在不同协议格式不一样。Internet协议上是一个元组(“127.0.0.1”,80) */</span></span><br><span class="line"></span><br><span class="line">socket	</span><br><span class="line"><span class="comment">/* 服务器正在监听的套接字对象 */</span></span><br><span class="line"></span><br><span class="line">request_queue_size	</span><br><span class="line"><span class="comment">/* 请求队列的大小。如果处理单个请求需要很长时间，那么在服务器繁忙时到达的任何请求都会被放入队列中，直到request_queue_size请求为止。一旦队列满了，来自客户机的进一步请求将得到一个“连接被拒绝”错误。默认值通常是5，但是可以被子类覆盖 */</span></span><br><span class="line"></span><br><span class="line">address_family	</span><br><span class="line"><span class="comment">/* 服务器套接字所属的协议族。常见的例子是套接字。AF_INET socket.AF_UNIX */</span></span><br><span class="line"></span><br><span class="line">socket_type	</span><br><span class="line"><span class="comment">/* 服务器使用的套接字类型;套接字。SOCK_STREAM套接字。SOCK_DGRAM是两个常见的值 */</span></span><br><span class="line"></span><br><span class="line">timeout	</span><br><span class="line"><span class="comment">/* 超时持续时间，以秒为单位度量，如果不需要超时，则为None。如果handle_request()在超时期间没有收到传入的请求，则调用handle_timeout()方法 */</span></span><br><span class="line"></span><br><span class="line">handle_request()	</span><br><span class="line"><span class="comment">/* 处理单个请求，同步执行</span></span><br><span class="line"><span class="comment">这个函数按顺序调用以下方法:get_request()、verify_request()和process_request()。如果处理程序类的用户提供的handle()方法引发异常，将调用服务器的handle_error()方法。如果在超时秒内没有收到任何请求，那么将调用handle_timeout()并返回handle_request() */</span></span><br><span class="line"></span><br><span class="line">server_forever(poll_interval=<span class="number">0.5</span>)	</span><br><span class="line"><span class="comment">/* 异步执行，处理请求。每隔poll_interval秒轮询一次。</span></span><br><span class="line"><span class="comment">忽略timeout属性，还会调用service_actions()，在ForkingMixIn的子类中定义，可以用来清理僵尸进程 */</span></span><br><span class="line"></span><br><span class="line">shutdown()	</span><br><span class="line"><span class="comment">/* 告诉serve_forever循环停止。并等待他结束 */</span></span><br><span class="line"></span><br><span class="line">server_close()	</span><br><span class="line"><span class="comment">/* 关闭服务器 */</span></span><br><span class="line"></span><br><span class="line">finish_request(request,client_address)	</span><br><span class="line"><span class="comment">/* 通过实例化RequestHandlerClass并调用它的handle()方法来处理请求 */</span></span><br><span class="line"></span><br><span class="line">server_bind()	</span><br><span class="line"><span class="comment">/* 由服务器的构造函数调用，以将套接字绑定到所需的地址。可能会被覆盖 */</span></span><br><span class="line"></span><br><span class="line">verify_request(request,client_address)	</span><br><span class="line"><span class="comment">/* 必须返回一个布尔值;如果值为True，请求将被处理，如果值为False，请求将被拒绝。可以重写此函数来实现服务器的访问控制。默认实现总是返回True */</span></span><br></pre></td></tr></table></figure>



<h4 id="BaseRequestHandler类"><a href="#BaseRequestHandler类" class="headerlink" title="BaseRequestHandler类"></a>BaseRequestHandler类</h4><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">&quot;&quot;&quot;</span></span><br><span class="line"><span class="string">是连接的用户请求处理类的基类</span></span><br><span class="line"><span class="string">request #是和客户端的连接的socket对象</span></span><br><span class="line"><span class="string">client_address #是客户端地址</span></span><br><span class="line"><span class="string">server #是TCPServer实例本身</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">&quot;&quot;&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">BaseRequestHandler</span>:</span><br><span class="line"></span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self, request, client_address, server</span>):</span><br><span class="line">        self.request = request</span><br><span class="line">        self.client_address = client_address</span><br><span class="line">        self.server = server</span><br><span class="line">        self.setup()</span><br><span class="line">        <span class="keyword">try</span>:</span><br><span class="line">            self.handle()</span><br><span class="line">        <span class="keyword">finally</span>:</span><br><span class="line">            self.finish()</span><br><span class="line"></span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">setup</span>(<span class="params">self</span>): <span class="comment">#每一个连接初始化</span></span><br><span class="line">        <span class="keyword">pass</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">handle</span>(<span class="params">self</span>): <span class="comment">#每一次请求处理</span></span><br><span class="line">        <span class="keyword">pass</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">finish</span>(<span class="params">self</span>): <span class="comment">#每一个连接清理</span></span><br><span class="line">        <span class="keyword">pass</span></span><br><span class="line"></span><br></pre></td></tr></table></figure>

<h4 id="案例1"><a href="#案例1" class="headerlink" title="案例1"></a>案例1</h4><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">&quot;&quot;&quot;服务端</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">&quot;&quot;&quot;</span></span><br><span class="line"><span class="keyword">import</span> socketserver</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">MyHandler</span>(socketserver.BaseRequestHandler):</span><br><span class="line"></span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">handle</span>(<span class="params">self</span>) -&gt; <span class="literal">None</span>:</span><br><span class="line">        <span class="keyword">while</span> <span class="literal">True</span>:</span><br><span class="line">            data = self.request.recv(<span class="number">1024</span>).decode()</span><br><span class="line">            <span class="keyword">if</span> data == <span class="string">&#x27;exit&#x27;</span>:</span><br><span class="line">                <span class="built_in">print</span>(<span class="string">&quot;客户端发送完成，断开连接。&quot;</span>)</span><br><span class="line">                <span class="keyword">break</span></span><br><span class="line">            <span class="built_in">print</span>(<span class="string">f&quot;接受到客户端 <span class="subst">&#123;self.client_address&#125;</span> 发来的消息： <span class="subst">&#123;data&#125;</span>&quot;</span>)</span><br><span class="line">            res = data.upper()</span><br><span class="line">            self.request.send(res.encode())</span><br><span class="line">        self.request.close()</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">hostaddress = (<span class="string">&quot;127.0.0.1&quot;</span>, <span class="number">8888</span>)</span><br><span class="line">server = socketserver.ThreadingTCPServer(hostaddress, MyHandler)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&quot;启动socket服务，等待客户端连接...&quot;</span>)</span><br><span class="line">server.serve_forever()</span><br></pre></td></tr></table></figure>



<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">&quot;&quot;&quot;客户端</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">&quot;&quot;&quot;</span></span><br><span class="line"><span class="keyword">import</span> socket</span><br><span class="line"></span><br><span class="line">serverddress = (<span class="string">&quot;127.0.0.1&quot;</span>, <span class="number">8888</span>)</span><br><span class="line"></span><br><span class="line">sk = socket.socket()</span><br><span class="line">sk.connect(serverddress)</span><br><span class="line"></span><br><span class="line"><span class="keyword">while</span> <span class="literal">True</span>:</span><br><span class="line">    data = <span class="built_in">input</span>(<span class="string">&quot;请输入信息：&quot;</span>).strip()</span><br><span class="line">    sk.sendall(data.encode())</span><br><span class="line">    <span class="keyword">if</span> data == <span class="string">&quot;exit&quot;</span>:</span><br><span class="line">        <span class="built_in">print</span>(<span class="string">&quot;客户端退出连接&quot;</span>)</span><br><span class="line">        <span class="keyword">break</span></span><br><span class="line">    anwser = sk.recv(<span class="number">1024</span>).decode()</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">f&quot;收到服务器应答： <span class="subst">&#123;anwser&#125;</span>&quot;</span>)</span><br><span class="line"></span><br><span class="line">sk.close()</span><br></pre></td></tr></table></figure>

<h4 id="案例2-使用socketserver实现群聊的server"><a href="#案例2-使用socketserver实现群聊的server" class="headerlink" title="案例2: 使用socketserver实现群聊的server"></a>案例2: 使用socketserver实现群聊的server</h4><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> logging</span><br><span class="line"><span class="keyword">import</span> sys</span><br><span class="line"><span class="keyword">import</span> socketserver</span><br><span class="line"><span class="keyword">import</span> socket</span><br><span class="line"><span class="keyword">import</span> threading</span><br><span class="line"></span><br><span class="line">logging.basicConfig(<span class="built_in">format</span>=<span class="string">&quot;%(asctime)s %(thread)d %(threadName)s %(message)s&quot;</span>,stream=sys.stdout,level=logging.INFO)</span><br><span class="line">log = logging.getLogger()</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Handler</span>(socketserver.BaseRequestHandler):</span><br><span class="line">    lock = threading.Lock()</span><br><span class="line">    clients = &#123;&#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">setup</span>(<span class="params">self</span>):</span><br><span class="line">        <span class="built_in">super</span>().setup()</span><br><span class="line">        self.event = threading.Event()</span><br><span class="line">        <span class="keyword">with</span> self.lock:</span><br><span class="line">            self.clients[self.client_address] = self.request</span><br><span class="line">        log.info(<span class="string">&quot;新加入了一个连接&#123;&#125;&quot;</span>.<span class="built_in">format</span>(self.client_address))</span><br><span class="line"></span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">handle</span>(<span class="params">self</span>):</span><br><span class="line">        <span class="built_in">super</span>().handle()</span><br><span class="line">        sock:socket.socket = self.request</span><br><span class="line">        <span class="keyword">while</span> <span class="keyword">not</span> self.event.is_set():</span><br><span class="line">            <span class="keyword">try</span>:</span><br><span class="line">                data = sock.recv(<span class="number">1024</span>)</span><br><span class="line">            <span class="keyword">except</span> Exception <span class="keyword">as</span> e:</span><br><span class="line">                log.error(e)</span><br><span class="line">                data = <span class="string">b&quot;&quot;</span></span><br><span class="line">            log.info(data)</span><br><span class="line">            <span class="keyword">if</span> data == <span class="string">b&quot;by&quot;</span> <span class="keyword">or</span> data == <span class="string">b&quot;&quot;</span>:</span><br><span class="line">                <span class="keyword">break</span></span><br><span class="line">            msg = <span class="string">&quot;service:&#123;&#125;--&gt;&#123;&#125;&quot;</span>.<span class="built_in">format</span>(self.client_address, data).encode()</span><br><span class="line">            expc = []  <span class="comment"># 记录sock出错时对应的clients</span></span><br><span class="line">            <span class="keyword">with</span> self.lock:</span><br><span class="line">                <span class="keyword">for</span> c, sk <span class="keyword">in</span> self.clients.items():</span><br><span class="line">                    <span class="keyword">try</span>:</span><br><span class="line">                        sk.send(msg)  <span class="comment"># 可能在发送消息是就出错</span></span><br><span class="line">                    <span class="keyword">except</span>:</span><br><span class="line">                        expc.append(c)</span><br><span class="line">                <span class="keyword">for</span> c <span class="keyword">in</span> expc:</span><br><span class="line">                    self.clients.pop(c)</span><br><span class="line"></span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">finish</span>(<span class="params">self</span>):</span><br><span class="line">        <span class="built_in">super</span>().finish()</span><br><span class="line">        self.event.<span class="built_in">set</span>()</span><br><span class="line">        <span class="keyword">with</span> self.lock:</span><br><span class="line">            <span class="keyword">if</span> self.client_address <span class="keyword">in</span> self.clients:</span><br><span class="line">                self.clients.pop(self.client_address)</span><br><span class="line">        self.request.close()</span><br><span class="line">        log.info(<span class="string">&quot;&#123;&#125;退出了&quot;</span>.<span class="built_in">format</span>(self.client_address))</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> __name__ == <span class="string">&quot;__main__&quot;</span>:</span><br><span class="line">    server = socketserver.ThreadingTCPServer((<span class="string">&quot;127.0.0.1&quot;</span>,<span class="number">3999</span>),Handler)</span><br><span class="line">    server.daemon_threads = <span class="literal">True</span>  <span class="comment">#设置所有创建的线程都为Daemo线程</span></span><br><span class="line">    threading.Thread(target=server.serve_forever,name=<span class="string">&quot;server&quot;</span>,daemon=<span class="literal">True</span>).start()</span><br><span class="line">    <span class="keyword">while</span> <span class="literal">True</span>:</span><br><span class="line">        cmd = <span class="built_in">input</span>(<span class="string">&quot;&gt;&gt;&gt;&quot;</span>)</span><br><span class="line">        <span class="keyword">if</span> cmd.strip() == <span class="string">&quot;quit&quot;</span>:</span><br><span class="line">            server.shutdown() <span class="comment">#告诉serve_forever循环停止。</span></span><br><span class="line">            server.server_close()</span><br><span class="line">            <span class="keyword">break</span></span><br><span class="line">        logging.info(threading.<span class="built_in">enumerate</span>())</span><br><span class="line"></span><br></pre></td></tr></table></figure>



<h3 id="UDP服务代码"><a href="#UDP服务代码" class="headerlink" title="UDP服务代码"></a>UDP服务代码</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">&quot;&quot;&quot;服务端</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">&quot;&quot;&quot;</span></span><br><span class="line"><span class="keyword">import</span> socketserver</span><br><span class="line"></span><br><span class="line">hostaddress = (<span class="string">&quot;127.0.0.1&quot;</span>, <span class="number">8888</span>)</span><br><span class="line"></span><br><span class="line">sk = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)</span><br><span class="line">sk.bind(hostaddress)</span><br><span class="line"></span><br><span class="line"><span class="keyword">while</span> <span class="literal">True</span>:</span><br><span class="line">    data = sk.recv(<span class="number">1024</span>).decode()</span><br><span class="line">    <span class="keyword">if</span> data == <span class="string">&#x27;exit&#x27;</span>:</span><br><span class="line">        <span class="built_in">print</span>(<span class="string">&quot;客户端退出&quot;</span>)</span><br><span class="line">        <span class="keyword">break</span></span><br><span class="line">    <span class="built_in">print</span>(<span class="string">f&quot;udp服务器接受到客户端发来的消息： <span class="subst">&#123;data&#125;</span>&quot;</span>)</span><br><span class="line"></span><br><span class="line">sk.close()</span><br></pre></td></tr></table></figure>



<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">&quot;&quot;&quot;客户端</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">&quot;&quot;&quot;</span></span><br><span class="line"><span class="keyword">import</span> socket</span><br><span class="line"></span><br><span class="line">serverddress = (<span class="string">&quot;127.0.0.1&quot;</span>, <span class="number">8888</span>)</span><br><span class="line"></span><br><span class="line">sk = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)</span><br><span class="line"></span><br><span class="line"><span class="keyword">while</span> <span class="literal">True</span>:</span><br><span class="line">    data = <span class="built_in">input</span>(<span class="string">&quot;请输入信息：&quot;</span>).strip()</span><br><span class="line">    sk.sendto(data.encode(), serverddress)</span><br><span class="line">    <span class="keyword">if</span> data == <span class="string">&#x27;exit&#x27;</span>:</span><br><span class="line">        <span class="built_in">print</span>(<span class="string">&quot;服务端退出&quot;</span>)</span><br><span class="line">        <span class="keyword">break</span></span><br><span class="line"></span><br><span class="line">sk.close()</span><br></pre></td></tr></table></figure>



<h3 id="参考链接"><a href="#参考链接" class="headerlink" title="参考链接"></a>参考链接</h3><font size=2>

<p>[1] <a target="_blank" rel="noopener" href="https://blog.csdn.net/qq_37193537/article/details/91043580">python之socket编程</a></p>
<p>[2] <a target="_blank" rel="noopener" href="https://blog.csdn.net/weixin_40895135/article/details/123418267">python Socket 参数详解</a></p>
<p>[3] <a target="_blank" rel="noopener" href="https://www.bilibili.com/video/BV1Fg4y1z7eP?p=21&vd_source=5f03bdbb9a8460c7ae08f9cdea23577b">socket网络编程</a></p>
<p>[4] <a target="_blank" rel="noopener" href="https://blog.csdn.net/u013008795/article/details/92642840">Python中的SocketServer模块</a></p>
</font>


    </div>

    
    
    

      <footer class="post-footer">

        


        
    <div class="post-nav">
      <div class="post-nav-item">
    <a href="/blog/2022/08/04/python%E5%BC%82%E5%B8%B8%E5%A4%84%E7%90%86/" rel="prev" title="python异常处理">
      <i class="fa fa-chevron-left"></i> python异常处理
    </a></div>
      <div class="post-nav-item">
    <a href="/blog/2022/08/08/python%E5%8F%8D%E5%B0%84/" rel="next" title="python反射">
      python反射 <i class="fa fa-chevron-right"></i>
    </a></div>
    </div>
      </footer>
    
  </article>
  
  
  



          </div>
          
    <div class="comments" id="valine-comments"></div>

<script>
  window.addEventListener('tabs:register', () => {
    let { activeClass } = CONFIG.comments;
    if (CONFIG.comments.storage) {
      activeClass = localStorage.getItem('comments_active') || activeClass;
    }
    if (activeClass) {
      let activeTab = document.querySelector(`a[href="#comment-${activeClass}"]`);
      if (activeTab) {
        activeTab.click();
      }
    }
  });
  if (CONFIG.comments.storage) {
    window.addEventListener('tabs:click', event => {
      if (!event.target.matches('.tabs-comment .tab-content .tab-pane')) return;
      let commentClass = event.target.classList[1];
      localStorage.setItem('comments_active', commentClass);
    });
  }
</script>


        </div>
          
  
  <div class="toggle sidebar-toggle">
    <span class="toggle-line toggle-line-first"></span>
    <span class="toggle-line toggle-line-middle"></span>
    <span class="toggle-line toggle-line-last"></span>
  </div>

  <aside class="sidebar">
    <div class="sidebar-inner">

      <ul class="sidebar-nav motion-element">
        <li class="sidebar-nav-toc">
          文章目录
        </li>
        <li class="sidebar-nav-overview">
          站点概览
        </li>
      </ul>

      <!--noindex-->
      <div class="post-toc-wrap sidebar-panel">
          <div class="post-toc motion-element"><ol class="nav"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E4%BB%80%E4%B9%88%E6%98%AFsocket"><span class="nav-number">1.</span> <span class="nav-text">什么是socket</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#socket%E7%BC%96%E7%A8%8B%E6%B5%81%E7%A8%8B"><span class="nav-number">2.</span> <span class="nav-text">socket编程流程</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#socket%E5%8F%82%E6%95%B0"><span class="nav-number">3.</span> <span class="nav-text">socket参数</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E7%AE%80%E5%8D%95%E7%9A%84%E6%9C%8D%E5%8A%A1%E5%99%A8%E5%92%8C%E5%AE%A2%E6%88%B7%E7%AB%AF%E9%80%9A%E4%BF%A1"><span class="nav-number">4.</span> <span class="nav-text">简单的服务器和客户端通信</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#socket%E6%96%87%E4%BB%B6%E4%BC%A0%E8%BE%93"><span class="nav-number">5.</span> <span class="nav-text">socket文件传输</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#socketserver"><span class="nav-number">6.</span> <span class="nav-text">socketserver</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#%E7%B1%BB%E7%9A%84%E7%BB%A7%E6%89%BF%E5%85%B3%E7%B3%BB"><span class="nav-number">6.1.</span> <span class="nav-text">类的继承关系</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#%E7%BC%96%E7%A8%8B%E6%8E%A5%E5%8F%A3"><span class="nav-number">6.2.</span> <span class="nav-text">编程接口</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#BaseRequestHandler%E7%B1%BB"><span class="nav-number">6.3.</span> <span class="nav-text">BaseRequestHandler类</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#%E6%A1%88%E4%BE%8B1"><span class="nav-number">6.4.</span> <span class="nav-text">案例1</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#%E6%A1%88%E4%BE%8B2-%E4%BD%BF%E7%94%A8socketserver%E5%AE%9E%E7%8E%B0%E7%BE%A4%E8%81%8A%E7%9A%84server"><span class="nav-number">6.5.</span> <span class="nav-text">案例2: 使用socketserver实现群聊的server</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#UDP%E6%9C%8D%E5%8A%A1%E4%BB%A3%E7%A0%81"><span class="nav-number">7.</span> <span class="nav-text">UDP服务代码</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%8F%82%E8%80%83%E9%93%BE%E6%8E%A5"><span class="nav-number">8.</span> <span class="nav-text">参考链接</span></a></li></ol></div>
      </div>
      <!--/noindex-->

      <div class="site-overview-wrap sidebar-panel">
        <div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
    <img class="site-author-image" itemprop="image" alt="bgape002"
      src="/blog/images/head.png">
  <p class="site-author-name" itemprop="name">bgape002</p>
  <div class="site-description" itemprop="description">mail: bgape002@163.com</div>
</div>
<div class="site-state-wrap motion-element">
  <nav class="site-state">
      <div class="site-state-item site-state-posts">
          <a href="/blog/archives/">
        
          <span class="site-state-item-count">61</span>
          <span class="site-state-item-name">日志</span>
        </a>
      </div>
      <div class="site-state-item site-state-categories">
            <a href="/blog/categories/">
          
        <span class="site-state-item-count">27</span>
        <span class="site-state-item-name">分类</span></a>
      </div>
      <div class="site-state-item site-state-tags">
            <a href="/blog/tags/">
          
        <span class="site-state-item-count">66</span>
        <span class="site-state-item-name">标签</span></a>
      </div>
  </nav>
</div>



      </div>

    </div>
  </aside>
  <div id="sidebar-dimmer"></div>


      </div>
    </main>

    <footer class="footer">
      <div class="footer-inner">
        

        

<div class="copyright">
  
  &copy; 2021 – 
  <span itemprop="copyrightYear">2023</span>
  <span class="with-love">
    <i class="fa fa-heart"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">bgape002</span>
</div>
  <div class="powered-by">由 <a href="https://hexo.io/" class="theme-link" rel="noopener" target="_blank">Hexo</a> & <a href="https://theme-next.org/" class="theme-link" rel="noopener" target="_blank">NexT.Gemini</a> 强力驱动
  </div>

        
<div class="busuanzi-count">
  <script async src="https://busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>
    <span class="post-meta-item" id="busuanzi_container_site_uv" style="display: none;">
      <span class="post-meta-item-icon">
        <i class="fa fa-user"></i>
      </span>
      <span class="site-uv" title="总访客量">
        <span id="busuanzi_value_site_uv"></span>
      </span>
    </span>
    <span class="post-meta-divider">|</span>
    <span class="post-meta-item" id="busuanzi_container_site_pv" style="display: none;">
      <span class="post-meta-item-icon">
        <i class="fa fa-eye"></i>
      </span>
      <span class="site-pv" title="总访问量">
        <span id="busuanzi_value_site_pv"></span>
      </span>
    </span>
</div>








      </div>
    </footer>
  </div>

  
  <script src="/blog/lib/anime.min.js"></script>
  <script src="/blog/lib/velocity/velocity.min.js"></script>
  <script src="/blog/lib/velocity/velocity.ui.min.js"></script>

<script src="/blog/js/utils.js"></script>

<script src="/blog/js/motion.js"></script>


<script src="/blog/js/schemes/pisces.js"></script>


<script src="/blog/js/next-boot.js"></script>




  




  
<script src="/blog/js/local-search.js"></script>











<script>
if (document.querySelectorAll('pre.mermaid').length) {
  NexT.utils.getScript('//cdn.jsdelivr.net/npm/mermaid@8/dist/mermaid.min.js', () => {
    mermaid.initialize({
      theme    : 'forest',
      logLevel : 3,
      flowchart: { curve     : 'linear' },
      gantt    : { axisFormat: '%m/%d/%Y' },
      sequence : { actorMargin: 50 }
    });
  }, window.mermaid);
}
</script>


  

  

  


<script>
NexT.utils.loadComments(document.querySelector('#valine-comments'), () => {
  NexT.utils.getScript('//unpkg.com/valine/dist/Valine.min.js', () => {
    var GUEST = ['nick', 'mail', 'link'];
    var guest = 'nick,mail';
    guest = guest.split(',').filter(item => {
      return GUEST.includes(item);
    });
    new Valine({
      el         : '#valine-comments',
      verify     : false,
      notify     : false,
      appId      : 'szhBf0Qamzsowubi1WnkXmUj-gzGzoHsz',
      appKey     : 'WpwxoK0fVJHvhzWwakr9vbpA',
      placeholder: "Just go go",
      avatar     : 'mm',
      meta       : guest,
      pageSize   : '10' || 10,
      visitor    : false,
      lang       : '' || 'zh-cn',
      path       : location.pathname,
      recordIP   : false,
      serverURLs : ''
    });
  }, window.Valine);
});
</script>

</body>
</html>
